package org.bigk.invoices.services;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.bigk.invoices.exceptions.ServiceException;
import org.bigk.invoices.model.Tax;
import org.bigk.invoices.services.taxesconfig.TaxConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service("taxesService")
@Transactional
public class TaxesServiceImpl implements TaxesService {

	private static final Logger logger = LoggerFactory.getLogger(TaxesServiceImpl.class);

	@PersistenceContext
	protected EntityManager em;
	
	@Autowired
	private TaxesConfigService taxesConfigService;
	
	@Override
	public List<Tax> listAllItems(Date date) throws ServiceException {
		logger.debug("listAllItems(date=[{}]) - start", date);

		// first read TaxConfig for given date
		Collection<Double> availTaxes = taxesAvailableForDate(date);
		
		CriteriaBuilder critBuilder = em.getCriteriaBuilder();
		CriteriaQuery<Tax> critQuery = critBuilder.createQuery(Tax.class);
		
		// select-clause
		Root<Tax> root = critQuery.from(Tax.class);
		
		critQuery.select(root);
		if (availTaxes != null) {
			critQuery.where(root.<Double>get("value").in(availTaxes));
		}
		critQuery.orderBy(critBuilder.asc(root.<Long>get("id")));
		
		List<Tax> list = em.createQuery(critQuery).getResultList();

		logger.debug("listAllItems(Date) - end - return value=" + CollectionUtils.size(list));
		return list;
	}

	private Collection<Double> taxesAvailableForDate(Date date) {
		Collection<Double> availTaxes = null;
		
		if (date != null) {
			TaxConfig tc = taxesConfigService.getTaxConfigByDate(date);
			logger.debug("listAllItems(Date) - read TaxConfig - tc=[{}]", tc);

			if (tc != null) {
				availTaxes = new ArrayList<Double>();
				availTaxes.add(NumberUtils.DOUBLE_ZERO);
				availTaxes.addAll(tc.getAvailTaxes());
				
				logger.debug("listAllItems(Date) - availTaxes=[{}]", availTaxes);
			}
		}
		return availTaxes;
	}
	
	@Override
	public Tax getTax(Long id) throws ServiceException {
		logger.debug("getTax(id=[{}]) - start", + id);

		Tax tax = em.find(Tax.class, id);

		logger.debug("getTax(Long) - end - return value=[{}]", tax);
		return tax;
	}
}
